/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLRegion.h>
#include <pgl/core/PGLRegionPropPage.h>
#include <pgl/core/PGLArchive.h>
#include <pgl/core/PGLLegend.h>
#include <pgl/core/PGLLine2D.h>
#include <pgl/core/PGLDataVectors.h>
#include <pgl/core/PGLDataTypes.h>
#include "../IGfx/GDILeak.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

PGL_IMPLEMENT_DYNCREATE(CPGLRegion,CPGLPave);

size_t CPGLRegion::GetNChildren() const	
{	
	return m_mChilds.GetCount();
};

//! Save settings
void CPGLRegion::SerializeXML(CPGLArchive& ar)
{
	static const TCHAR szTag[] = _T("CPGLRegion");

	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if (ar.IsStoring())
	{
		xml.AddChildElem(szTag);
		xml.AddChildAttrib(_T("Name"),GetName());
		xml.IntoElem();
			// subclass
			CPGLPave::SerializeXML(ar);

			// axis
			m_axe.SerializeXML(ar);
			xml.AddChildElemEx(_T("ChildFirst"),m_bChildFirst);
	
			// objects...
			if (!m_mObjects.IsEmpty())
			{
				xml.AddChildElem(_T("Objects"));
				xml.IntoElem();
					m_mObjects.SerializeXML(ar);
				xml.OutOfElem();
			}

			// serialize childs
			if (!m_mChilds.IsEmpty())
			{
				xml.AddChildElem(_T("Childs"));
				xml.IntoElem();
					m_mChilds.SerializeXML(ar);
				xml.OutOfElem();
			}
			
			xml.AddChildElemEx(_T("Angle"), m_dAngle);
		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;
		// erasing previous data
		DeleteAllObjects();

		// entering element
		xml.IntoElem();
			// subclass
			CPGLPave::SerializeXML(ar);
	
			// Axis
			xml.ResetChildPos();
			m_axe.SerializeXML(ar);
			xml.FindGetChildData(_T("ChildFirst"),m_bChildFirst);

			// objects...
			xml.ResetChildPos();
			if (xml.FindChildElem(_T("Objects")))
			{
				xml.IntoElem();
					m_mObjects.SerializeXML(ar);
				xml.OutOfElem();
			}

			// serialize childs
			xml.ResetChildPos();
			if (xml.FindChildElem(_T("Childs")))
			{
				xml.IntoElem();
					m_mChilds.SerializeXML(ar);
				xml.OutOfElem();
			}

			xml.FindGetChildData(_T("Angle"), m_dAngle);
		xml.OutOfElem();
	}
}

#ifdef _DEBUG
void CPGLRegion::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLPave::Dump( dc );

    // now do the stuff for our specific class
	// now dumping..
	dc << _T("--- CPGLRegion ---\n")<< "\n";
    dc << m_view<<"\n";
}
void CPGLRegion::AssertValid() const
{
    // call inherited AssertValid first
    CPGLPave::AssertValid();

    // check members...
	m_view.AssertValid();
    // check members...
	m_axe.AssertValid();
} 
#endif

CPGLRegion::CPGLRegion()
: m_dAngle(0), m_bChildFirst(false)
{
	m_axe.SetParent(CPGLRegionStPtr(this));
	m_axe.SetView(&m_view);

	m_mObjects.SetParent(CPGLRegionStPtr(this));
	m_mChilds.SetParent(CPGLRegionStPtr(this));

	SetSolidFillColor(0.82f,0.82f,0.82f);
	LoadBitmap(IDB_PGL_REGION_BITMAP);
}

CPGLRegion& CPGLRegion::operator =(const CPGLRegion& g)
{
	if (&g!=this)
	{
		CPGLPave::operator =(g);

		m_view=g.m_view;
		m_axe=g.m_axe;
		m_mObjects=g.m_mObjects;
		m_mChilds=g.m_mChilds;
		m_dAngle = g.m_dAngle;
		m_bChildFirst = g.m_bChildFirst;

		PostUpdateGraph();
		LoadBitmap(IDB_PGL_REGION_BITMAP);
	}
	return *this;
}

CPGLRegion::~CPGLRegion()
{
	Delete();
}

/// adds pObject to the graph (memory must be allowed by user)
void CPGLRegion::AddObject(CPGLObjectPtr pObject)
{	
	if (!pObject)
		return;
	ASSERT(! pObject->IsKindOf( RUNTIME_CLASS(CPGLRegion) ) );

	// check there's no duplicate...
	if ( m_mObjects.IsIn( pObject->GetID() ) )
		return;

	// setting parent pointer
	pObject->SetParent(CPGLRegionStPtr(this));
	// adding pointer
	m_mObjects.AddTail(pObject); 
	PostUpdateGraph();
	// updating graph
}

/// adds pObject to the graph (memory must be allowed by user)
void CPGLRegion::AddObjectBack(CPGLObjectPtr pObject)
{	
	if (!pObject)
		return;
	ASSERT(! pObject->IsKindOf( RUNTIME_CLASS(CPGLRegion) ) );

	// check there's no duplicate...
	if ( m_mObjects.IsIn( pObject->GetID() ) )
		return;

	// setting parent pointer
	pObject->SetParent(CPGLRegionStPtr(this));
	// adding pointer
	m_mObjects.AddHead(pObject); 
	// updating graph
	PostUpdateGraph();
}


CPGLRegionPtr CPGLRegion::AddRegion()
{
	CPGLRegionPtr pNewRegion = CPGLRegionPtr(new CPGLRegion());

	// adding pointer
	m_mChilds.AddTail(pNewRegion); 

	// setting parent pointer
	pNewRegion->SetParent(CPGLRegionStPtr(this));
	// updating graph
	PostUpdateGraph();

	return pNewRegion;
}

CPGLRegionPtr CPGLRegion::AddRegionBack()
{
	CPGLRegionPtr pNewRegion = CPGLRegionPtr(new CPGLRegion());

	// adding pointer
	m_mChilds.AddHead(pNewRegion); 
	// setting parent pointer
	pNewRegion->SetParent(CPGLRegionStPtr(this));
	// updating graph
	PostUpdateGraph();

	return pNewRegion;
}

void CPGLRegion::UnhideAll()
{
	CPGLObjectManager::Container::iterator it;
	for (it=m_mObjects.begin(); it!= m_mObjects.end();++it)
	{
		(*it)->Show();
	}

	CPGLRegionManager::Container::iterator rit;
	for (rit=m_mChilds.begin(); rit!= m_mChilds.end();++rit)
	{
		(*it)->Show();
	}
}

void CPGLRegion::GetUnionExtent(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExtent)
{
	CPGLRectD rExtentTemp;
	CPGLObjectPtr pObject;
	bool firstx=true;
	bool firsty=true;


	// no object case
	if (m_mObjects.IsEmpty())
	{
		rExtent=CPGLRectD::GetNormBox();
		SetExtent(CPGLRectD::GetNormBox());
		return;
	}

	// first, non text objects.
	rExtentTemp.xValid=false;
	rExtentTemp.yValid=false;
	rExtentTemp.left= std::numeric_limits<double>::max();
	rExtentTemp.right= -std::numeric_limits<double>::max();
	rExtentTemp.bottom= std::numeric_limits<double>::max();
	rExtentTemp.top= -std::numeric_limits<double>::max();

	// getting extent...
	CPGLObjectManager::Container::const_iterator it;
	for (it=m_mObjects.begin(); it!= m_mObjects.end();++it)
	{
		pObject=*it;
		if (!pObject)
			continue;

		if (!pObject->IsVisible())
			continue;

		// test for type...
		pObject->GetUnionExtent(gfx,rExtentTemp);

		// testing...
		if (rExtentTemp.xValid)
		{
			rExtent.left=rExtentTemp.left;
			rExtent.right=rExtentTemp.right;
		}

		if (rExtentTemp.yValid)
		{
			rExtent.top=rExtentTemp.top;
			rExtent.bottom=rExtentTemp.bottom;
		}
	}

	// testing if too smalll
	if ( rExtent.IsWidthEmpty())
	{
		rExtent.left-=0.5f;
		rExtent.right+=0.5f;
	}
	if ( rExtent.IsHeightEmpty() )
	{
		rExtent.bottom-=0.5f;
		rExtent.top+=0.5f;
	}

	// testing if too big
   if ( boost::test_tools::tt_detail::fpt_abs( rExtent.left) >= std::numeric_limits<float>::max() )
	{
		if (rExtent.left>0)
			rExtent.left=std::numeric_limits<float>::max()/100;
		else
			rExtent.left=-std::numeric_limits<float>::max()/10;
	}
	if ( boost::test_tools::tt_detail::fpt_abs(rExtent.right) >= std::numeric_limits<float>::max() )
	{
		if (rExtent.right>0)
			rExtent.right=std::numeric_limits<float>::max()/10;
		else
			rExtent.right=-std::numeric_limits<float>::max()/100;
	}
	if ( boost::test_tools::tt_detail::fpt_abs(rExtent.top) >= std::numeric_limits<float>::max() )
	{
		if (rExtent.top>0)
			rExtent.top=std::numeric_limits<float>::max()/10;
		else
			rExtent.top=-std::numeric_limits<float>::max()/100;
	}
	if ( boost::test_tools::tt_detail::fpt_abs(rExtent.bottom) >= std::numeric_limits<float>::max() )
	{
		if (rExtent.bottom>0)
			rExtent.bottom=std::numeric_limits<float>::max()/100;
		else
			rExtent.bottom=-std::numeric_limits<float>::max()/10;
	}
	

	SetExtent(rExtent);
}

void CPGLRegion::Delete()
{
	PGL_TRACE(_T("Starting cleaning\n"));

	// deleting objects
	DeleteAllObjects();

	PGL_TRACE(_T("Fonts unassigned\n"));

	// Post updating
	PostUpdateGraph();
	PGL_TRACE(_T("Cleaning success\n"));
}

void CPGLRegion::UpdateGraph(gfxinterface::CGfxInterface& gfx)
{	
	CPGLRectD rExt;
	// retreive info
	m_axe.GetLimits(rExt);

	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating extent to put axis
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	m_view.ZoomAll(rExt.left,rExt.right,rExt.bottom,rExt.top);
	
	// update labels
	m_axe.UpdateLabels(gfx);
	m_bNeedUpdate=FALSE;

	// computing child viewports
	CPGLRegionManager::Container::iterator it;
	for (it=m_mChilds.begin(); it!= m_mChilds.end();it++)
	{
		(*it)->UpdateGraph(gfx);
	}
};

void CPGLRegion::SetViewport(int tx, int ty, int width, int height)
{
	CPGLRectD rNormBBox = GetOutsideBBox();
	// computing own viewport
	m_view.SetViewport(
		tx + (int) floor(width * rNormBBox.left),
		ty + (int) floor(height * rNormBBox.bottom),
		(int) floor(width * rNormBBox.GetWidth()),
		(int) floor(height * rNormBBox.GetHeight()) );

	// computing child viewports
	CPGLRegionManager::Container::iterator it;
	for (it=m_mChilds.begin(); it!= m_mChilds.end();++it)
	{
		(*it)->SetViewport(m_view.GetTx(), m_view.GetTy(), m_view.GetWidth(), m_view.GetHeight());
	}
};

void CPGLRegion::ZoomAll(gfxinterface::CGfxInterface& gfx, bool recurse)
{
	// computing extent extent
	CPGLRectD rExt, rExtNew;

	GetUnionExtent(gfx,rExt);

	// updating extent to put axis
	rExtNew=rExt;

	// updating axis
	m_axe.SetLimits(rExtNew, gfx);

	// retreive info
	m_axe.GetLimits(rExtNew);

	// grow window
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExtNew);
	}
	else
	{
		// updating extent to put axis
		// updating with region borders...
		m_axe.GrowExtent(rExtNew,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	// updating view
	m_view.ZoomAll(rExtNew.left,rExtNew.right,rExtNew.bottom,rExtNew.top);

	if (recurse)
	{
		CPGLRegionManager::Container::iterator it;
		for (it=m_mChilds.begin(); it!= m_mChilds.end();++it)
		{
			(*it)->ZoomAll(gfx,true);
		}
	}
}

void CPGLRegion::ZoomRegion(gfxinterface::CGfxInterface& gfx, CPGLRectD& rExt)
{
	// updating axis
	m_axe.SetLimits(rExt, gfx);

	// retreive info
	m_axe.GetLimits(rExt);


	// updating extent to put axis
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	// updating view
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);
}

void CPGLRegion::ZoomBox(gfxinterface::CGfxInterface& gfx, int xStart, int yStart, int xEnd, int yEnd)
{
	// putting start and end in order
	int temp;
	if (xStart>xEnd)
	{
		temp=xStart;
		xStart=xEnd;
		xEnd=temp;
	}
	// y is going down
	if (yStart<yEnd)
	{
		temp=yStart;
		yStart=yEnd;
		yEnd=temp;
	}
	// checking that box has at least 1 of size
	if (xStart==xEnd)
		xEnd++;
	if (yStart==yEnd)
		yEnd++;

	// step 1 setting axis
	// sending dimension of box to axe and computing box
	CPGLRectD rExt(m_view.PixelToWorldCoord(0,xStart),
		m_view.PixelToWorldCoord(1,yStart),
		m_view.PixelToWorldCoord(0,xEnd),
		m_view.PixelToWorldCoord(1,yEnd));
	m_axe.SetLimits(rExt, gfx); //top

	// retreivinf info
	m_axe.GetLimits(rExt);

	// Step 2 grow extent
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating extent to put axis
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	// Step 3, updating view
	ASSERT(rExt.left <= rExt.right);
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);
}

void CPGLRegion::ZoomIn(gfxinterface::CGfxInterface& gfx)
{
	// step 1 zoom in of view
	m_view.ZoomIn();

	// step 2 set axis
	CPGLRectD rExt(m_view.GetLeft(),m_view.GetBottom(),m_view.GetRight(),m_view.GetTop());
	m_axe.SetLimits(rExt, gfx); //top

	// retreivinf info
	m_axe.GetLimits(rExt);

	// Step 2 grow extent
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating extent to put axis
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	// Step 3, updating view
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);
}

void CPGLRegion::ZoomOut(gfxinterface::CGfxInterface& gfx)
{
	// step 1 zoom in of view
	m_view.ZoomOut();

	// step 2 set axis
	CPGLRectD rExt(m_view.GetLeft(),m_view.GetBottom(),m_view.GetRight(),m_view.GetTop());
	m_axe.SetLimits(rExt, gfx); //top

	// retreivinf info
	m_axe.GetLimits(rExt);

	// Step 2 grow extent
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating extent to put axis
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	// Step 3, updating view
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);
}


void CPGLRegion::Pan(int x, int y)
{
	// step 1 pan view
	m_view.Pan(x,y);
	m_axe.Pan(m_view.PixelToWorld(0,x),m_view.PixelToWorld(1,y));
}

void CPGLRegion::ZoomScale(double x, double y)
{
	// step 1 pan view
	m_view.ZoomScale(x,y);
	m_axe.ZoomScale(x,y);

	bool bAutoStepsx = m_axe.IsAutoSteps(CPGLAxe2D::AxisHorizontal);
	bool bAutoStepsy = m_axe.IsAutoSteps(CPGLAxe2D::AxisVertical);
	// retreive info
	m_axe.SetAutoSteps(CPGLAxe2D::AxisHorizontal,false);
	m_axe.SetAutoSteps(CPGLAxe2D::AxisVertical,false);

	CPGLRectD rExt;
	m_axe.GetLimits(rExt);


	// updating extent to put axis
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating with region borders...
		m_axe.GrowExtent(rExt,&(GetBorderSize()), &(GetInsideBorderSize()));
	}

	m_axe.SetAutoSteps(CPGLAxe2D::AxisHorizontal,bAutoStepsx);
	m_axe.SetAutoSteps(CPGLAxe2D::AxisVertical,bAutoStepsy);

	// updating view
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);

}

void CPGLRegion::DeleteAllObjects()
{
	// Remove objects
	m_mObjects.Clear();
	m_mChilds.Clear();
}

void CPGLRegion::SetNormBBox(const CPGLRectD& rNormBBox)
{
	GetArea().SetArea(rNormBBox,CPGLArea2D::CoordNorm);
}

void CPGLRegion::SetNormBBox(float llx, float lly, float urx, float ury)
{
	CPGLRectD rNormBBox;
	// make lower left corner and upper right are ordered
	rNormBBox.left = __max(0, __min(llx, urx));
	rNormBBox.right = __min(1, __max(llx, urx));
	rNormBBox.bottom = __max(0, __min(lly, ury));
	rNormBBox.top = __min(1, __max(lly, ury));

	GetArea().SetArea(rNormBBox, CPGLArea2D::CoordNorm);
}

void CPGLRegion::AddPropertyPage(CPropertySheet* pPropSheet)
{
	ASSERT_VALID(pPropSheet);
	// call own functions
	CPGLRegionPropPage* propPage=new CPGLRegionPropPage(this);
	pPropSheet->AddPage(propPage);

	// first call base class function
	CPGLPave::AddPropertyPage(pPropSheet);
}

HTREEITEM CPGLRegion::AddPropTree(CTreeCtrl* pTree, HTREEITEM hParent)
{
	ASSERT_VALID(pTree);
	CString str;

	CImageList* pImgList=pTree->GetImageList(TVSIL_NORMAL);
	ASSERT_VALID(pImgList);
	ASSERT(hParent);
	COLORREF crMask=0;

	// adding bitmap
	pImgList->Add(CBitmap::FromHandle(GetBitmap()),crMask);

	// adding to tree
	HTREEITEM pRegionItem;
	HTREEITEM pObjItem;
	HTREEITEM pRgnItem;

	// inserting object root
	pRegionItem=pTree->InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM   /* nMask*/, 
				GetName() /* lpszItem*/, 
				pImgList->GetImageCount()-1 /* nImage */, 
				0 /* nSelectedImage */, 
				0  /* nState */, 
				0 /* nStateMask */, 
				GetID() /*  lParam */, 
				hParent /* hParent */, 
				TVI_LAST /* hInsertAfter */);
	ASSERT(pRegionItem!=NULL);

	// insert axis
	// adding to tree
	HTREEITEM pAxeItem=m_axe.AddPropTree(pTree,pRegionItem);
	ASSERT(pAxeItem!=NULL);
	// check if selected...
//	if ((long)m_axe.GetID()==m_lSelID)
//		pTree->SelectItem(pAxeItem);

	// filling up insert structure with objects
	CPGLObjectManager::Container::iterator it;
	for (it=m_mObjects.begin(); it!= m_mObjects.end();it++)
	{

		pObjItem=(*it)->AddPropTree(pTree,pRegionItem);
		ASSERT(pObjItem!=NULL);
	}

	// filling up insert structure with subplots
	CPGLRegionManager::Container::iterator rit;
	for (rit=m_mChilds.begin(); rit!= m_mChilds.end();++rit)
	{
		pRgnItem=(*rit)->AddPropTree(pTree,pRegionItem);
		ASSERT(pRgnItem!=NULL);
	}

	return pRegionItem;
}

void CPGLRegion::Divide(int nrows, int ncols)
{
	using namespace markup;

	CMarkupArchive xml;

	xml.AddElem(_T("layout"));
	xml.AddChildElem(_T("matrix"));
	xml.AddChildAttribEx(_T("nrows"),nrows);
	xml.AddChildAttribEx(_T("ncols"),ncols);
	
	Layout( xml.GetDoc() );
}

namespace pgl
{
	namespace priv
	{
		typedef std::list<CPGLRectD> ListRectD;
		// worker function
		static void ParseLayout( markup::CMarkupArchive& xml, ListRectD& lRects, ListRectD::iterator itCur)
		{
			ASSERT(!lRects.empty());
			if (itCur==lRects.end())
				return;

			float llx, lly, urx, ury;
			ListRectD lCurRects;
			ListRectD::iterator it;
			std::vector<ListRectD::iterator> vCurRectsIts;
			std::vector<float> vXpos;
			std::vector<float> vYpos;
			CPGLRectD curRect;
			size_t nrows=1, ncols=1;
			int i,j;
			
			// only 1 child
			if(xml.FindChildElem(_T("matrix")))
			{
				// getting current region ID
				curRect=*itCur;
				// getting number of rows and columns
				nrows=xml.GetChildAttribUINT(_T("nrows"));
				ncols=xml.GetChildAttribUINT(_T("ncols"));
				
				nrows=__max(nrows,1);
				ncols=__max(ncols,1);

				// getting vector of position...
				xml.GetChildAttribEx(_T("xpos"), vXpos);			
				xml.GetChildAttribEx(_T("ypos"), vYpos);			
				
				// checking data
				for (i=1;i<static_cast<int>(vXpos.size());++i)
				{
					if (vXpos[i-1]>=vXpos[i])
						vXpos.clear();
				}

				// checking data
				for (i=1;i<static_cast<int>(vYpos.size());++i)
				{
					if (vYpos[i-1]<=vYpos[i])
						vYpos.clear();
				}
				
				vCurRectsIts.resize(nrows*ncols);
				// creating list of rects...
				for (i=nrows-1;i>=0;--i)
				{
					if (nrows-i<vYpos.size() && vYpos[nrows-i]>=0 && vYpos[nrows-i]<=1)
						lly=static_cast<float>(curRect.bottom+vYpos[nrows-i]*curRect.GetHeight());
					else
						lly =static_cast<float>(curRect.bottom+(float)((double) i / (double) (nrows))*curRect.GetHeight());

					if (nrows-(i+1)<vYpos.size() && vYpos[nrows-(i+1)]>=0 && vYpos[nrows-(i+1)]<=1)
						ury = static_cast<float>(curRect.bottom+vYpos[nrows-(i+1)]*curRect.GetHeight());
					else
						ury = static_cast<float>(curRect.bottom+(float)((double) (i+1) / (double) (nrows))*curRect.GetHeight());

					for (j=0;j<static_cast<int>(ncols);++j)
					{
						if (i<static_cast<int>(vXpos.size()) && vXpos[j]>=0 && vXpos[j]<=1)
							llx = static_cast<float>(curRect.left+vXpos[j]*curRect.GetWidth());
						else
							llx = static_cast<float>(curRect.left+(float)((double) j / (double) (ncols))*curRect.GetWidth());

						if (j+1<static_cast<int>(vXpos.size()) && vXpos[j+1]>=0 && vXpos[j+1]<=1)
							urx = static_cast<float>(curRect.left+vXpos[j+1]*curRect.GetWidth());
						else
							urx = static_cast<float>(curRect.left+(float)((double) (j+1) / (double) (ncols))*curRect.GetWidth());
						
						// adding rect...
						lCurRects.push_back( CPGLRectD(llx, lly, urx, ury));
					} // end for j
				} // end for i
				
				// filling vector...
				for (i=0, it=lCurRects.begin();i<static_cast<int>(nrows*ncols);++i, ++it)
					vCurRectsIts[i]=it;
				
				// now parsing subobjects...
				xml.IntoElem();
				while (xml.FindChildElem(_T("child")))
				{
					i=xml.GetChildAttribUINT(_T("index"));
					
					if (i<0 || i>=static_cast<int>(vCurRectsIts.size()))
						continue;
					
					xml.IntoElem();
					// parsing child...
					ParseLayout(xml, lCurRects, vCurRectsIts[i]);
					xml.OutOfElem();
				} // end while
				xml.OutOfElem();
				
				// merging list
				lRects.splice(itCur,lCurRects);
				lRects.erase(itCur);
			} // endif xml.findChildElem
		}
	}
}

bool CPGLRegion::Layout(LPCTSTR szXMLLayout)
{
	using namespace pgl::priv;
	using namespace markup;

	CMarkupArchive xml;

	if (!xml.LoadString(szXMLLayout))
		return false;

	if (!xml.FindElem(_T("layout")))
		return false;

	// deleting all objects
	DeleteAllObjects();
	
	// hiding axis and borders
	m_axe.Hide();
	SetBorderType(CPGLPave::BorderNone);
	
	ListRectD lRects;
	lRects.push_front( CPGLRectD::GetNormBox());

	ParseLayout(xml, lRects, lRects.begin());

	// adding regions
	CPGLRegionPtr pRegion;
	ListRectD::const_iterator it;
	CString str;
	size_t i;

	for (it = lRects.begin(), i=0; it!=lRects.end();++it, ++i)
	{
		pRegion = AddRegion();
		pRegion->SetNormBBox(*it);
		str.Format(_T("Subplot %d"),i);
		pRegion->SetName(str);
		pRegion->GetAxe()->SetTitle(str);
	}

	return true;
}

CPGLRegionPtr CPGLRegion::GetChild(size_t i)
{
	return m_mChilds[i];
}

void CPGLRegion::DeleteChild(size_t i)
{
	CPGLRegionPtr pRegion = m_mChilds[i];
	if (pRegion)
		m_mChilds.RemoveObject(pRegion);
}

void CPGLRegion::DeleteChildWithObjects(CPGLRegionPtr regionPtr)
{
   unsigned int numberOfChilds = m_mChilds.GetCount();
   for(unsigned int i = 0; i < numberOfChilds; ++i)
   {
      if (m_mChilds[i] == regionPtr) // If the region is found, remove all objects contained on it
      {
         CPGLObjectManager& manager = regionPtr->GetObjectManager();
         // Remove all objects
         while(manager.GetCount())
         {
            manager.RemoveObject(manager[0]);
         }
         m_mChilds.RemoveObject(m_mChilds[i]); // Remove the child region
         break;
      }
   }
}

void CPGLRegion::DeleteObject(size_t i)
{
	CPGLObjectPtr pObject = m_mObjects[i];
	if (pObject)
		m_mObjects.RemoveObject(pObject);
}

void CPGLRegion::PlotGfx(gfxinterface::CGfxInterface& gfx)
{	
	CString str;

	// updating graph
//	UpdateGraph();

	GFX_ADDCOMMENT(gfx,"--- CPGLRegion ---");
	gfx.PushState();
	gfx.PushBBox();
		// rotatin region if necessary
		if (m_dAngle)
		{
			CPGLPointD  poCenter=GetArea().GetBBox().GetCenter();
			gfx.Rotate(m_dAngle, poCenter.x,poCenter.y);
		}
		// drawing background...
		gfx.PushState();
		CPGLPave::PlotGfx(gfx);
		gfx.PopState();

		if (m_bChildFirst)
		{
			// Drawing childs
			m_mChilds.PlotGfx(gfx);
			// setting bounding box
			m_view.PlotGfx(gfx);
			// plotting the axe
			m_axe.PlotGfx(gfx);
			if (! m_mObjects.IsEmptyLayer(gfx))
			{
				// setting clipping path
				m_axe.ClipGfx(gfx);
				// plot objects
				m_mObjects.PlotGfx(gfx);
				// remove clipping path
				m_axe.UnClipGfx(gfx);
			}
		}
		else
		{

			// setting bounding box
			m_view.PlotGfx(gfx);
			// plotting the axe
			m_axe.PlotGfx(gfx);
			if (! m_mObjects.IsEmptyLayer(gfx))
			{
				// setting clipping path
				m_axe.ClipGfx(gfx);
				// plot objects
				m_mObjects.PlotGfx(gfx);
				// remove clipping path
				m_axe.UnClipGfx(gfx);
			}
			// Drawing childs
			m_mChilds.PlotGfx(gfx);
		}
		
	gfx.PopState();
	gfx.PopBBox();
};

CPGLLegendPtr CPGLRegion::AddLegend()//CPGLLegend::ELegendPos eLegendPos)
{
	CPGLLegendPtr pLegend = CPGLLegendPtr(new CPGLLegend());
	pLegend->SetPosition( CPGLLegend::LegendPosUpperRight );
//	pLegend->SetPosition( eLegendPos );

	m_mObjects.PushLinesTop(pLegend);

	AddObject(pLegend);

	return pLegend;
}

long CPGLRegion::FindPointedRegion(gfxinterface::CGfxInterface &gfx, const CPGLPointD &point)
{
	// first check if inside pave...
	if ( ! GetArea().IsPointInside(gfx, point) )
	{
		return 0;
	}

	if (m_mChilds.GetCount())
	{
		// set world view...
		gfx.PushBBox();
		// setting bounding box
		m_view.PlotGfx(gfx);
		// ok inside region, check if inside any child
		long uRegionID = m_mChilds.FindPointedRegion(gfx,point);
		// restor views
		gfx.PopBBox();

		if (uRegionID)
			return uRegionID;
	}

	return GetID();
}

void CPGLRegion::RefreshView(gfxinterface::CGfxInterface &gfx, bool bRecurse, bool bRefreshAxis)
{
	CPGLRectD rExt;
	// updating numbering if needed
	if (bRefreshAxis)
	{
		m_axe.GenerateSteps(CPGLAxe2D::AxisHorizontal);
		m_axe.GenerateSteps(CPGLAxe2D::AxisVertical);
	}

	//updating labels
	m_axe.UpdateLabels(gfx);

	// retreive info
	m_axe.GetLimits(rExt);

	// updating extent to put axis
	if (GetBorderType() & CPGLPave::BorderNone)
	{
		// updating extent to put axis
		m_axe.GrowExtent(rExt);
	}
	else
	{
		// updating with region borders...
		m_axe.GrowExtent(rExt, &(GetBorderSize()), &(GetInsideBorderSize()));
	}
	
	// updating view
	m_view.ZoomAll(rExt.left, rExt.right, rExt.bottom, rExt.top);	

	if (bRecurse)
	{
		CPGLRegionManager::Container::iterator it;
		for (it=m_mChilds.begin(); it!= m_mChilds.end();it++)
		{
			(*it)->RefreshView(gfx, bRecurse, bRefreshAxis);
		}
	}
}

void CPGLRegion::PushWorldClipBBox(gfxinterface::CGfxInterface &gfx)
{
	gfx.PushState();
	gfx.PushBBox();
	m_view.PlotGfx(gfx);
	m_axe.ClipGfx(gfx);
}

void CPGLRegion::PopWorldClipBBox(gfxinterface::CGfxInterface &gfx)
{
	m_axe.UnClipGfx(gfx);
	gfx.PopState();
	gfx.PopBBox();
}

bool CPGLRegion::LoadCSVFile(LPCTSTR szFileName)
{
	// get data...
	parsers::CDataFile csvreader;

	if (!csvreader.ReadDataFile( szFileName ))
		return false;

	LPCTSTR szSmallFileName=_tcsrchr(szFileName ,'\\');
	if (!szSmallFileName)
		szSmallFileName=szFileName;
	else
		szSmallFileName=_tcsinc(szSmallFileName);
	
	const parsers::CDataFile::NamedVectorContainer& vs = csvreader.GetData();

	PGL_TRACE2(_T("Importing CSV File: %d columns, %d lines\n"), vs.size(), (vs.size()) ? vs[0].second.size() : 0 );

	CPGLLine2DPtr pLine;
	CPGLVectorFPtr pX;
	switch( vs.size())
	{
	case 0:
		break;
	case 1:
		pLine = CPGLLine2DPtr(new CPGLLine2D);
		pLine->SetDatas( CPGLLinearVectorPtr(new CPGLLinearVector( 0, 1, vs[0].second.size())) , CPGLVectorFPtr(new CPGLVectorF( vs[0].second )) );
		pLine->SetName( szSmallFileName );
		pLine->SetLineWidth(2);
		AddObject(pLine);
		break;
	case 2:
		pLine = CPGLLine2DPtr(new CPGLLine2D);
		pLine->SetDatas( CPGLVectorFPtr(new CPGLVectorF( vs[0].second )) , CPGLVectorFPtr(new CPGLVectorF( vs[1].second )) );
		pLine->SetName( szSmallFileName );
		pLine->SetLineWidth(2);
		pLine->SetColor( CPGLColor::GetClassicColor( (CPGLColor::EColor)(rand()%139) ) );
		AddObject(pLine);
		break;			
	default:
		pX = CPGLVectorFPtr( CPGLVectorFPtr( new CPGLVectorF( vs[0].second )) );
		for (size_t i=1;i<vs.size();++i)
		{
			pLine = CPGLLine2DPtr(CPGLLine2DPtr(new CPGLLine2D));
			pLine->SetDatas( pX , CPGLVectorFPtr(new CPGLVectorF( vs[i].second )) );
			pLine->SetName( vs[i].first );
			pLine->SetLineWidth(2);
			pLine->SetColor( CPGLColor::NextClassicColor() );
			AddObject(pLine);
		}
	}

	return true;
}

CPGLRegionStPtr CPGLObject::GetParent()
{	
	return m_pParent;
};

void CPGLObject::SetParent(CPGLRegionStPtr pParent)	
{	
	m_pParent = pParent;
};

CPGLObjectManager& CPGLRegion::GetObjectManager()
{	
	return m_mObjects;
};

const CPGLObjectManager& CPGLRegion::GetObjectManager()	const		
{	
	return m_mObjects;
};
	
CPGLRegionManager& CPGLRegion::GetChildManager()					
{	
	return m_mChilds;
};
	
const CPGLRegionManager& CPGLRegion::GetChildManager() const		
{	
	return m_mChilds;
};
